use std::time::Duration;

use super::proto::read_status;
use crate::{error::AppErr, global::APP};
use tokio::{
    io::BufReader,
    net::TcpStream,
    sync::mpsc,
    time::timeout,
};



pub struct RobotStatusListener {
    stream: BufReader<TcpStream>,
}

pub enum ListenerCmd {
    Disconnect,
}

type RobotCmdRx = mpsc::Receiver<ListenerCmd>;
pub type RobotCmdTx = mpsc::Sender<ListenerCmd>;

impl RobotStatusListener {

    pub async fn connect(address: String) -> Result<RobotCmdTx, AppErr> {
        let stream = Self::connect_impl(&address).await?;
        let listener = RobotStatusListener {
            stream: BufReader::with_capacity(1024, stream),
        };
        let (tx, rx) = mpsc::channel(5);
        tokio::spawn(listener.read_task(address, rx));
        Ok(tx)
    }

    async fn read_task(mut self, address: String, mut rx: RobotCmdRx) {
        APP.notify_info("机械臂读取启动");

        loop {
            tokio::select! {
                _ = rx.recv() => {
                    break;
                }

                ret = self.read_loop() => {
                    match ret {
                        Ok(()) => {
                            break;
                        }
                        Err(e) => {
                            log::error!("robot status err:{}", e);
                        }
                    };
                }
            };
            APP.notify_info("机械臂状态 断开 启动重连...");
            if let Err(_) = self.reconnect_loop(&address, &mut rx).await {
                break;
            }
        }
        APP.notify_info("机械臂读取退出");
    }

    async fn reconnect_loop(&mut self, address: &str, rx: &mut RobotCmdRx) -> Result<(), AppErr> {
        loop {
            APP.notify_info("机械臂状态连接 重新连接");

            tokio::select! {
                _ = rx.recv() => {
                    return Err(AppErr::Static("机械臂状态 收到退出命令"));
                },

                ret = self.reconnect(&address) => {
                    if ret.is_ok() {
                        break;
                    }
                }
            }

            match timeout(Duration::from_secs(5), rx.recv()).await {
                Ok(_) => {
                    return Err(AppErr::Static("机械臂状态 收到退出命令"));
                }
                Err(_) => {}
            };
        }

        Ok(())
    }

    async fn reconnect(&mut self, address: &str) -> Result<(), AppErr> {
        let stream = Self::connect_impl(address).await?;
        self.stream = BufReader::with_capacity(1024, stream);
        Ok(())
    }

    async fn read_loop(&mut self) -> Result<(), AppErr> {
        loop {
            let status = read_status(&mut self.stream).await?;
            APP.notify_robot_status(status).await;
        }
    }

    async fn connect_impl(address: &str) -> Result<TcpStream, AppErr> {
        let ret = timeout(Duration::from_secs(5), TcpStream::connect(address))
            .await
            .map_err(|_| AppErr::Static("机械臂状态连接超时"))??;
        Ok(ret)
    }
}
